#pragma once
#include "util.hpp"
#include "online.hpp"
#include "db.hpp"
#include "room.hpp"
#include <list>
#include <mutex>
#include <condition_variable>
/*
    匹配队列管理模块
*/

template <class T>
class match_queue
{
public:
    void push(const T &data)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _list.push_back(data);
        _cond.notify_all();
    }

    bool pop(T &data)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        if (_list.empty())
            return false;
        data = _list.front();
        _list.pop_front();
        return true;
    }

    void remove(const T &data)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _list.remove(data);
    }

    int size()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        return _list.size();
    }

    bool empty()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        return _list.empty();
    }

    void wait()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _cond.wait(lock);
    }

private:
    std::condition_variable _cond;
    std::mutex _mutex;
    std::list<T> _list;
};

class macher
{
private:
    void handle_match(match_queue<uint64_t> &mq)
    {
        while (true)
        {
            while (mq.size() < 2)
            {
                mq.wait();
            }
            uint64_t user1;
            bool ret = mq.pop(user1);
            if (ret == false)
            {
                continue;
            }
            uint64_t user2;
            ret = mq.pop(user2);
            if (ret == false)
            {
                // 是否此时应该头插入匹配队列？？？
                mq.push(user1);
                continue;
            }

            wsserver_t::connection_ptr conn1 = _online_m->get_conn_from_hall(user1);
            if (conn1.get() == nullptr)
            {
                mq.push(user2);
                continue;
            }

            wsserver_t::connection_ptr conn2 = _online_m->get_conn_from_hall(user2);
            if (conn1.get() == nullptr)
            {
                mq.push(user1);
                continue;
            }

            //创建一个房间 将匹配成功的玩家 加入其中
            room_ptr rp = _room_m->create_room(user1, user2);
            if (rp.get() == nullptr)
            {
                mq.push(user1);
                mq.push(user2);
                continue;
            }
                //5. 对两个玩家进行响应
                Json::Value resp;
                resp["optype"] = "match_success";
                resp["result"] = true;
                std::string body;
                json_util::serialize(resp, body);
                conn1->send(body);
                conn2->send(body);
        }
    }
    void th_junior_entry() { return handle_match(_q_junior); }
    void th_mediate_entry() { return handle_match(_q_mediate); }
    void th_senior_entry() { return handle_match(_q_senior); }

public:
    macher(online_manager *om, user_table *ut, room_manager *rm)
        : _online_m(om),
          _user_m(ut),
          _room_m(rm),
          _t_junior(std::thread(&macher::th_junior_entry, this)),
          _t_mediate(std::thread(&macher::th_mediate_entry, this)),
          _t_senior(std::thread(&macher::th_senior_entry, this))
    {
        LOG(INFO, "匹配模块加载成功\n");
    }

    bool add(uint64_t uid)
    {
        Json::Value user;
        bool ret = _user_m->select_by_id(uid, user);
        if (ret == false)
        {
            LOG(DEBUG, "玩家信息获取失败\n");
            return false;
        }
        int score = user["score"].asInt();
        if (score < 2000)
        {
            _q_junior.push(uid);
        }
        else if (score >= 2000 && score < 3000)
        {
            _q_mediate.push(uid);
        }
        else
        {
            _q_senior.push(uid);
        }
        return true;
    }
    bool del(uint64_t uid)
    {
        Json::Value user;
        bool ret = _user_m->select_by_id(uid, user);
        if (ret == false)
        {
            LOG(DEBUG, "玩家信息获取失败\n");
            return false;
        }
        int score = user["score"].asInt();
        if (score < 2000)
        {
            _q_junior.remove(uid);
        }
        else if (score >= 2000 && score < 3000)
        {
            _q_mediate.remove(uid);
        }
        else
        {
            _q_senior.remove(uid);
        }
        return true;
    }

private:
    online_manager *_online_m;
    user_table *_user_m;
    room_manager *_room_m;
    match_queue<uint64_t> _q_junior;
    match_queue<uint64_t> _q_mediate;
    match_queue<uint64_t> _q_senior;
    std::thread _t_junior;
    std::thread _t_mediate;
    std::thread _t_senior;
};